home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '91 / '91 Attendee Contributions / Rotate Src / Rotate.a.old < prev    next >
Encoding:
Text File  |  1991-06-20  |  13.6 KB  |  483 lines  |  [TEXT/MPS ]

  1. ;    Bitmap rotation routines
  2.  
  3. ;    Copyright © 1989 Bob Spence
  4. ;    All rights reserved.
  5.  
  6.     INCLUDE 'QuickEqu.a'
  7.     INCLUDE 'Traps.a'
  8.  
  9. ;
  10. ; Rotation States
  11. ;
  12. ;    no rotation        rotate 180
  13. ;    (0)    1 2            (X)    4 3
  14. ;        3 4                2 1
  15. ;
  16. ;    mirror            mirror
  17. ;    horizontal        vertical
  18. ;    (H)    2 1            (V)    3 4
  19. ;        4 3                1 2
  20. ;
  21. ;    rotate left        rotate right
  22. ;    (L)    2 4            (R    3 1
  23. ;        1 3                4 2
  24. ;
  25. ;     flip left         flip right
  26. ;  (FL)    1 3           (FR)    4 2
  27. ;        2 4                3 1
  28. ;
  29.  
  30. ;
  31. ;    Rotation State Table
  32. ;
  33. ;              Rotate  Mirror  Mirror  Rotate  Rotate
  34. ;      State       180      Horiz       Vert       Left      Right        FL        FR
  35. ;        0        X        H        V        L        R        FL        FR
  36. ;        H        V        0        X        FL        FR        L        R
  37. ;        V        H        X        0        FR        FL        R        L
  38. ;        X        0        V        H        R        L        FR        FL
  39. ;        L        R        FR        FL        X        0        H        V
  40. ;        R        L        FL        FR        0        X        V        H
  41. ;       FL        FR        R        L        V        H        0        X
  42. ;       FR        FL        L        R        H        V        X        0
  43. ;
  44.  
  45. ; typedef enum {Rot0, RotH, RotV, RotX,
  46. ;                RotL, RotR, RotFR, RotFL} RotationSw;
  47.  
  48. Rot0    EQU    0
  49. RotH    EQU    1
  50. RotV    EQU    2
  51. RotX    EQU    3
  52. RotL    EQU    4
  53. RotR    EQU    5
  54. RotFL    EQU    6
  55. RotFR    EQU    7
  56.  
  57. ; PROCEDURE CalcRotate(OldState, NewRotate: RotationSw): RotationSw;
  58. ; parameter offsets (in Pascal order)
  59. NEW_ROTATE    EQU 4+4
  60. OLD_STATE    EQU NEW_ROTATE+4
  61.  
  62.     EXPORT    CALC_ROTATE
  63. CALC_ROTATE    PROC
  64.     Link    A6,#0
  65.     Move.L    OLD_STATE(A6),D0     ; Get the rotation state
  66.     Lsl.W    #3,D0
  67.     Add.W    NEW_ROTATE(A6),D0 ; Apply the new rotation
  68.     And.W    #$3F,D0
  69.     Move.L    RotState,A0        ; Point to the transformation table
  70.     Move.B    (A0,D0.W),-2(A6) ; Return the resultant rotation state
  71.     Unlk    A6
  72.     Move.L    (sp)+,A0        ; Get return address and
  73.     Add.L    #8,sp            ; pop parameters off stack
  74.     Jmp        (A0)            ; for a Pascal style return
  75.  
  76. RotState    ; Indexed by state and rotation, giving new rotation state
  77.     DC.B     Rot0, RotX, RotH, RotV, RotL, RotR, RotFL,RotFR
  78.     DC.B    RotH, RotV, Rot0, RotX, RotFL,RotFR,RotL, RotR
  79.     DC.B    RotV, RotH, RotX, Rot0, RotFR,RotFL,RotR, RotL
  80.     DC.B    RotX, Rot0, RotV, RotH, RotR, RotL, RotFR,RotFL
  81.     DC.B    RotL, RotR, RotFR,RotFL,RotX, Rot0, RotH, RotV
  82.     DC.B    RotR, RotL, RotFL,RotFR,Rot0, RotX, RotV, RotH    
  83.     DC.B    RotFL,RotFR,RotR, RotL, RotV, RotH, Rot0, RotX
  84.     DC.B    RotFR,RotFL,RotL, RotR, RotH, RotV, RotX, Rot0
  85.  
  86.     ENDPROC
  87.     
  88. ;    The user may also select rotation of the image 90° left, right, or
  89. ;     180° as well as mirroring of the image horizontally and vertically.
  90.  
  91.  
  92.  
  93. ; Register usage
  94. ;    A0 = Input bitmap or current data pointer
  95. ;    A1 = Output bitmap or current data pointer
  96. ;    D0 & D1 = temp variables
  97. ;    D2..D7  = part of 16 word rotation matrix
  98.  
  99. ; Named register storage
  100.  
  101. InBase        EQU A2            ; Input BitMap row base address (when rotated)
  102. OutBase        EQU A2            ; Output BitMap row base address (when mirrored)
  103. InBytes        EQU A3            ; Input BitMap rowBytes
  104. xD0            EQU    A4            ; Temp storage for D0 in D0..D7 data block
  105. xD1            EQU    A5            ; Temp storage for D1 in D0..D7 data block
  106.  
  107. ; Local variable stack offsets
  108.  
  109. RowPtr        EQU    -4            ; Temp storage for output word pointer
  110. LowBound    EQU    RowPtr-4    ; Lowest output word address
  111. HiBound        EQU    LowBound-4    ; Highest output word address
  112. OutBytes    EQU    HiBound-2    ; Output BitMap rowBytes 
  113. InWords        EQU    OutBytes-2    ; Words in an input row (-1 for Dbra))
  114. InRows        EQU    InWords-2    ; Rows in the input BitMap
  115. OutRows        EQU    InRows-2    ; Rows in the output BitMap
  116. WordCnt        EQU    OutRows-2    ; Temp storage for Word loop counter
  117. LOCALSZ        EQU    WordCnt-2    ; Total space needed for local variables
  118.  
  119. ; The following Macros are used to:
  120. ;    Initialize the rotation loops
  121. ;    Load registers with input to transform
  122. ;    Transform the data
  123. ;    Loop thru the data as needed, and return
  124.  
  125. ;    
  126. ; Macros used to rotate a BitMap [left, right, flip left, flip right]
  127. ;
  128. ; Used by LOAD_REGS to fill a D register with the next 2 column words
  129.     MACRO
  130.     LOAD_REG    &Dreg
  131.     Move.W    (A0),&Dreg        ; Get a word
  132.     Add.L    InBytes,A0        ; Drop to next row
  133.     Swap    &Dreg            ; Put it into hi word
  134.     Move.W    (A0),&Dreg        ; Get a word
  135.     Add.L    InBytes,A0        ; Drop to next row
  136.     Swap    &Dreg            ; Restore 1st word low, 2nd word hi
  137.     ENDM
  138.  
  139. ; Establish the tops of the 16 word block rotate loops and
  140. ; load a 16 word block of data to rotate in the D registers
  141.     MACRO
  142.     LOAD_REGS &Loop
  143.     Move.L    A1,RowPtr(A6)    ; Save output's word address
  144. &Loop.Col:                    ; Top of the column loop
  145.     Move.W    InWords(A6),D0    ; Word count to process, this row
  146. &Loop.Row:                    ; Top of the row loop
  147.     Move.W    D0,WordCnt(A6)    ; Save loop counter, we need D0
  148.     Move.L    A0,InBase        ; Save the current input address
  149.     ; generate LOAD_REG D0..D7
  150.     LCLA    &n
  151. &n    SETA    0
  152.     WHILE    &n <= 7 DO
  153.     LOAD_REG D&n
  154. &n    SETA    &n + 1
  155.     ENDW
  156.     Move.L    D0,xD0            ; Save working D0 and D1 regs
  157.     Move.L    D1,xD1
  158.     Add.L    #2,InBase        ; Point to next input word block
  159.     Move.L    InBase,A0        ; Restore the start of input
  160.     Move.W    #15,D0            ; Do 16 Dbra loops
  161. &Loop.Word:                    ; Top of the 16 bit loop
  162.     Swap    D0                ; Save bit loop count, we need a word D0
  163.     ENDM
  164.  
  165. ; Rotate a bit from the left or right (&fr) of each word in Dx
  166. ; into the left or right (&to) of the D0 result word
  167.     MACRO
  168.     RotREG &fr,&to,&Dreg
  169.     Rox&fr..W    #1,&Dreg    ; Get an input bit
  170.     Rox&to..W    #1,D0        ; Set the output bit
  171.     Swap        &Dreg        ; Get the 2nd, hi word
  172.     Rox&fr..W    #1,&Dreg    ; Get the next input bit
  173.     Rox&to..W    #1,D0        ; Set the output bit
  174.     Swap        &Dreg        ; Restore hi and lo words
  175.     ENDM
  176.     
  177. ; Get 16 bits from the 16 Dx words, rotated into D0
  178.     MACRO
  179.     ROT_REGS &fr,&to
  180.     ; generate RotREG D0..D7
  181.     LCLA    &n
  182. &n    SETA    0
  183.     WHILE    &n <= 7 DO
  184.     IF        &n <= 1 THEN
  185.     Move.L    xD&n,D1            ; xD0 and xD1 share D1
  186.     RotREG    &fr,&to,D1
  187.     Move.L    D1,xD&n
  188.     ELSE
  189.     RotREG    &fr,&to,D&n
  190.     ENDIF
  191. &n    SETA    &n+1
  192.     ENDW
  193.     Move.W    D0,(A1)            ; Store the rotated output word
  194.     ENDM
  195.  
  196. ; Check the word, row and column loops, cleanup, and return
  197.     MACRO
  198.     END_ROTATE &Loop,&AdSb1,&AdSb2
  199.     &AdSb1..W OutBytes(A6),A1 ; Add/Subtract to next output row
  200.     Swap    D0                ; Get the bit loop count
  201.     IF &AdSb1 = 'Add' THEN
  202.     CMP.L    HiBound(A6),A1    ; If slop on the bottom been exceeded,
  203.     BGT.s    &Loop.End        ;  we will go to next column
  204.     ELSE
  205.     CMP.L    LowBound(A6),A1    ; If slop on the bottom been rotated up,
  206.     BLT.s    &Loop.End        ;  we will go to next column
  207.     ENDIF
  208.     Dbra    D0,&Loop.Word
  209. &Loop.End
  210.     Move.W    WordCnt(A6),D0    ; Get row width word loop count
  211.     Dbra    D0,&Loop.Row
  212.     &AdSb2..L #2,RowPtr(A6)    ; Add/Sub to next output word of row
  213.     Move.L    RowPtr(A6),A1    ; Restore to start of next output word
  214.     Move.L    InBytes,D0        ; Get the input rowBytes
  215.     Lsl.L    #4,D0            ; A0 has wrapped to 1st column, 2nd word
  216.     Sub.L    InBytes,D0        ; so offset = 15 * InBytes
  217.     Add.L    D0,A0            ; Point to next A0 in word 15 rows beyond
  218.     Sub.W    #16,InRows(A6)    ; Drop down to rotate next 16 rows
  219.     Bgt        &Loop.Col        ; When the rows are zero, we're done
  220.     ENDM
  221. ;
  222. ; Macros to mirror BitMaps [horizontal, vertical, 180°, null]
  223. ;
  224. ; Establish the tops of the mirroring loops
  225.     MACRO
  226.     GET_REG &Loop
  227. &Loop.Col:
  228.     Move.L    A1,OutBase        ; Save the start of output
  229.     Move.W    D1,D2            ; Set the Width loop count
  230. &Loop.Row:
  231.     ENDM
  232.  
  233. ; Transfer a word from input to output, unchanged
  234.     MACRO
  235.     GET_WORD    
  236.     Move.W    (A0)+,D0        ; Just get an input word, it's Ok as is
  237.     Move.W    D0,(A1)+        ; Store the word
  238.     ENDM
  239.  
  240. ; Transfer a word from input to output, bits reversed
  241.     MACRO
  242.     REVERSE_REG    
  243.     Move.W    (A0)+,D3        ; Reverse the 16 bits in word D3 
  244.     LCLA    &n
  245. &n    SETA    0
  246.     WHILE    &n <= 15 DO
  247.     Roxr.W    #1,D3            ; Take a bit from the right
  248.     Roxl.W    #1,D0            ;  and insert it to the left
  249. &n    SETA    &n + 1
  250.     ENDW
  251.     Move.W    D0,-(A1)        ; Store the word
  252.     ENDM
  253.  
  254. ; Check the word, row and column loops, cleanup, and return
  255.     MACRO
  256.     END_MIRROR &Loop,&ASub
  257.                             ; Loop,Add/Sub
  258.     Dbra    D2,&Loop.Row    ; Loop thru row's width
  259.     Move.L    OutBase,A1        ; Restore to start of row
  260.     &ASub..L InBytes,A1        ; Add/Sub to next row
  261.     Sub.W    #1,InRows(A6)    ; Drop to next row
  262.     Bgt.s    &Loop.Col        ; When the rows are zero, we're done
  263.     ENDM
  264.  
  265. ; Shift words left by the slop bits    
  266.     MACRO
  267.     SHIFT_WORDS
  268.     LCLA    &n
  269. &n    SETA    0
  270.     WHILE    &n <= 7 DO
  271.     Move.W    -(A0),D0    ; Get a word in the low word
  272.     Rol.L    D4,D0        ; Shift out the slop bits, round in good ones
  273.     Move.W    D0,(A0)        ; Store good word
  274.     Rol.L    D3,D0        ; Shift remaining good bits to top of long word
  275. &n    SETA    &n + 1
  276.     ENDW
  277.     ENDM    
  278.  
  279. ;
  280. ; The bit rotation routine
  281. ; PROCEDURE Rotate (sourceMap, destMap: bitMap);
  282. ;
  283. ; Initialize loops, jump to specific rotation macros, and return
  284. ;
  285. ; parameter offsets (in Pascal order)
  286. DEST_MAP    EQU 4+4
  287. SOURCE_MAP    EQU DEST_MAP+4
  288. ROTATION    EQU SOURCE_MAP+4
  289.  
  290. Btop         EQU  D1     ; Some BitMap bounds Rect defines
  291. Bleft        EQU  D2    
  292. Bbottom        EQU  D3
  293. Bright        EQU  D4
  294.  
  295.     EXPORT    ROTATE
  296. ROTATE    PROC
  297.     Link    A6,#LOCALSZ              ; Allocate temporary storage
  298.     Movem.L    D2-D7/A2-A5,-(sp)     ; D0-D1/A0-A1 are scratch in Pascal and C
  299.     Move.L    SOURCE_MAP(A6),A2     ; Get the source BitMap address
  300.     Move.L    DEST_MAP(A6),A1          ; Get the destination BitMap address
  301.     Moveq    #0,D0
  302.     Move.L    D0,D1
  303.     Move.W    rowBytes(A2),D1        ; Get the input rowBytes
  304.     Move.L    D1,InBytes            ; Set the row byte count
  305.     Lsr.W    #1,D1                ; Convert to words
  306.     Sub.W    #1,D1                ;  minus 1 (for Dbra)
  307.     Move.W    D1,InWords(A6)
  308.     Movem.W    bounds(A2),D1-D4    ; Get the source bounds Rect
  309.     Move.W    Bbottom,D0
  310.     Sub.W    Btop,D0
  311.     Move.W    D0,InRows(A6)        ; Set the input number of rows
  312.     Cmp.B    #RotL,ROTATION(A6)    ; Is the destination not rotated
  313.     Blt.s    NoRotate
  314.     Sub.W    Bright,D0            ; Rotate the bounds Rect
  315.     Add.W    Bleft,D0            ; (Bbottom - Btop) - (Bright - Bleft);
  316.     Sub.W    D0,Bbottom
  317.     Add.W    D0,Bright
  318. NoRotate
  319.     Movem.W    D1-D4,bounds(A1) ; Set the destination bounds Rect
  320.     Move.W    Bbottom,D5
  321.     Sub.W    Btop,D5
  322.     Move.W    D5,OutRows(A6)    ; Set the destination row count
  323.  
  324.     Move.W    Bright,D6        ; Compute rowBytes
  325.     Sub.W    Bleft,D6        ;  forced to word boundary
  326.     Add.W    #15,D6
  327.     Lsr.W    #4,D6            ; (Bright - Bleft + 15) / 16) * 2
  328.     Lsl.W    #1,D6
  329.     Move.W    D6,rowBytes(A1)    ; Set the destination rowBytes
  330.     Move.W    D6,OutBytes(A6)
  331.     Mulu    D6,D5            ; Compute destination map size
  332.     Addq    #2,D5            ;  rowBytes * (Bbottom - Btop)
  333.     Move.L    D5,D0            ;  plus a fudge word for slop bits
  334.     Addq    #2,D0            ;  plus one more slop word
  335.     _NewPtr                    ; allocate space for bitmap
  336.     Move.L    A0,baseAddr(A1)    ; Set the destination upper left corner
  337.     Move.L    A0,LowBound(A6)    ; Save lowest output address
  338.     Add.L    D5,A0            ; Point beyond lower right corner
  339.     Move.L    A0,HiBound(A6)    ; Save Highest output address
  340.     Move.L    baseAddr(A2),A0    ; Get the source upper left corner
  341.     Move.W    InWords(A6),D1    ; Set D1 for GET_REG Macro
  342.  
  343.     Moveq    #0,D0
  344.     Move.B    ROTATION(A6),D0    ; Get the rotation type
  345.     And.W    #7,D0            ; Force to legal, We provide no error check, yet
  346.     Add.W    D0,D0
  347.     Move.W    Jump_Table(PC,D0),D0
  348.     Jmp        Jump_Table(PC,D0)
  349.  
  350. Jump_Table
  351.     DC.W    (Rotate_0 - Jump_Table)
  352.     DC.W    (Rotate_H - Jump_Table)
  353.     DC.W    (Rotate_V - Jump_Table)
  354.     DC.W    (Rotate_X - Jump_Table)
  355.     DC.W    (Rotate_L - Jump_Table)
  356.     DC.W    (Rotate_R - Jump_Table)
  357.     DC.W    (Rotate_FL - Jump_Table)
  358.     DC.W    (Rotate_FR - Jump_Table)
  359. ;
  360. ; The Rotation and Mirror Routines
  361. ;
  362. Rotate_0                        
  363.     Move.L        LowBound(A6),A1    ; Point to upper left corner
  364.     GET_REG        loop0
  365.     GET_WORD
  366.     END_MIRROR    loop0,Add
  367.     Bra            Exit_Rotate
  368.  
  369. Rotate_H
  370.     Move.L        LowBound(A6),A1    ; Point beyond upper right corner
  371.     Add.W        InBytes,A1        ; for predecrement of A1 in data stores
  372.     GET_REG        loopH
  373.     REVERSE_REG
  374.     END_MIRROR    loopH,Add
  375.     Bra            Shift_Left        ; shift image left slop bits
  376.  
  377. Rotate_V
  378.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  379.     Sub            #2,A1            ; and never slop adjust
  380.     Sub.W        InBytes,A1
  381.     GET_REG        loopV
  382.     GET_WORD
  383.     END_MIRROR    loopV,Sub
  384.     Bra            Exit_Rotate
  385.  
  386. Rotate_X
  387.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  388.                                 ; for predecrement of A1 in data stores
  389.     Move.L        DEST_MAP(A6),A4          ; Get the destination BitMap address
  390.     Move.W        bounds+right(A4),D3
  391.     Sub.W        bounds+left(A4),D3    ; Number of slop bits on the left
  392.     And.W        #$0F,D3                ; Any slop bits to shift in a word ?
  393.     Sub            #2,A1            ; We don't slop adjust later in Shift_Left
  394.     GET_REG        loopX
  395.     REVERSE_REG
  396.     END_MIRROR    loopX,Sub
  397.     Bra            Shift_Left        ; shift image left slop bits
  398.  
  399. Rotate_L
  400.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  401.     Sub.W        OutBytes(A6),A1    ; Point to lower left corner
  402.     Sub            #2,A1            ; and never slop adjust
  403.     LOAD_REGS    loopL
  404.     ROT_REGS    l,l
  405.     END_ROTATE    loopL,Sub,Add
  406.     Bra            Exit_Rotate
  407.  
  408. Rotate_R
  409.     Move.L        LowBound(A6),A1
  410.     Add.W        OutBytes(A6),A1
  411.     Sub.L        #2,A1            ; Point to upper right corner
  412.     LOAD_REGS    loopR
  413.     ROT_REGS    l,r
  414.     END_ROTATE    loopR,Add,Sub
  415.     Bra            Shift_Left        ; shift image left slop bits
  416.  
  417. Rotate_FL
  418.     Move.L        LowBound(A6),A1    ; Point to upper left corner
  419.     LOAD_REGS    loopFL
  420.     ROT_REGS    l,l
  421.     END_ROTATE    loopFL,Add,Add
  422.     Bra            Exit_Rotate
  423.  
  424. Rotate_FR
  425.     Move.L        HiBound(A6),A1    ; Point beyond lower right corner
  426.     Sub.L        #2,A1            ; Point to lower right corner
  427.     Move.L        DEST_MAP(A6),A4          ; Get the destination BitMap address
  428.     Move.W        bounds+right(A4),D3
  429.     Sub.W        bounds+left(A4),D3    ; Number of slop bits on the left
  430.     And.W        #$0F,D3                ; Any slop bits to shift in a word ?
  431.     Sub            #2,A1            ; We don't slop adjust later in Shift_Left
  432.     LOAD_REGS    loopFR
  433.     ROT_REGS    l,r
  434.     END_ROTATE    loopFR,Sub,Sub
  435. ;;    Bra            Shift_Left        ; shift image left slop bits
  436.  
  437. ;
  438. ; Routines to shift the BitMap data for any slop around
  439. ; the edges caused by images having heights or widths
  440. ; which are not on word boundaries. Some rotations cause 
  441. ; extra columns or rows to be generated to the left or top
  442. ; of the BitMap, we now must push the image up to the topLeft
  443. ; corner of the Bitmap.
  444. ;
  445. ; Shift left the output BitMap any slop columns
  446. Shift_Left
  447.     Move.L    DEST_MAP(A6),A4          ; Get the destination BitMap address
  448.     Move.W    bounds+right(A4),D3
  449.     Sub.W    bounds+left(A4),D3    ; Number of slop bits on the left
  450.     And.W    #$0F,D3                ; Any slop bits to shift in a word ?
  451.     Beq.s    Exit_Rotate
  452.     Move.L    baseAddr(A4),A0    ; Get the destination upper left corner
  453.     Move.W    OutBytes(A6),D1
  454.     Move.W    OutRows(A6),D2    ; Get the output rows
  455.     Mulu    D1,D2            ; Get total byte size
  456.     Add.L    D2,A0            ; Point to lower right corner
  457.     Lsr.W    #1,D2            ; Convert to words
  458.     Moveq    #16,D4
  459.     Sub.W    D3,D4            ; Number of slop bits
  460.     Move.L    D2,D5
  461.     Lsr.L    #3,D5            ; Loop count in blocks of 8 words
  462.     Move.W    D2,D1
  463.     Neg.W    D1                ; To jump into the loop doing the 
  464.     And.W    #7,D1            ;  block boundary remainder first
  465.     Beq.s    Bit_Loop_End
  466.     Asl.W    #3,D1            ; Multiply by code block size
  467.     Jmp        Bit_loop(PC,D1)    ; Jump into the loop, part way
  468. Bit_loop
  469.     SHIFT_WORDS
  470. Bit_Loop_End
  471.     Dbra    D5,Bit_loop
  472.     
  473. Exit_Rotate
  474.     Movem.L    (sp)+,D2-D7/A2-A5
  475.     Unlk    A6
  476.     Move.L    (sp)+,A0        ; Get return address and
  477.     Add.L    #10,sp            ; pop parameters off stack
  478.     Jmp        (A0)            ; for a Pascal style return
  479.     ENDPROC
  480.     
  481.     END
  482.